BemÀstra avancerade funktioner i Fetch API: request interception för dynamiska Àndringar och svarscaching för förbÀttrad prestanda i globala webbappar.
Avancerad Fetch API: Request Interception vs. Svarscaching för globala webbapplikationer
I den stĂ€ndigt förĂ€nderliga vĂ€rlden av webbutveckling Ă€r prestanda och responsivitet av yttersta vikt. För en global publik, dĂ€r nĂ€tverkslatens och anslutningsstabilitet kan variera dramatiskt, Ă€r optimering av hur vĂ„ra applikationer hĂ€mtar och hanterar data inte bara en god praxis â det Ă€r en nödvĂ€ndighet. Fetch API, en modern standard för att göra nĂ€tverksanrop i JavaScript, erbjuder kraftfulla funktioner som strĂ€cker sig bortom enkla GET- och POST-anrop. Bland dessa avancerade funktioner utmĂ€rker sig request interception och svarscaching som avgörande tekniker för att bygga robusta och effektiva globala webbapplikationer.
Det hÀr inlÀgget kommer att gÄ pÄ djupet med bÄde request interception och svarscaching med hjÀlp av Fetch API. Vi kommer att utforska deras grundlÀggande koncept, praktiska implementeringsstrategier och hur de kan utnyttjas synergistiskt för att skapa en överlÀgsen anvÀndarupplevelse för anvÀndare över hela vÀrlden. Vi kommer ocksÄ att diskutera övervÀganden för internationalisering och lokalisering vid implementering av dessa mönster.
FörstÄ grundkoncepten
Innan vi dyker ner i detaljerna, lÄt oss klargöra vad request interception och svarscaching innebÀr i kontexten av Fetch API.
Request Interception
Request interception avser förmÄgan att fÄnga upp utgÄende nÀtverksanrop som görs av din JavaScript-kod innan de skickas till servern. Detta gör att du kan:
- Modifiera anrop: LÀgga till anpassade headers (t.ex. autentiseringstokens, API-versionering), Àndra anropets body, Àndra URL:en eller till och med avbryta ett anrop under vissa förhÄllanden.
- Logga anrop: SpÄra nÀtverksaktivitet för felsökning eller analysÀndamÄl.
- Mocka anrop: Simulera serversvar under utveckling eller testning utan att behöva en live-backend.
Ăven om Fetch API i sig inte erbjuder en direkt, inbyggd mekanism för att fĂ„nga upp anrop pĂ„ samma sĂ€tt som vissa tredjepartsbibliotek eller Ă€ldre XMLHttpRequest (XHR) intercepts fungerade, möjliggör dess flexibilitet att vi kan bygga robusta mönster för interception, framför allt genom Service Workers.
Svarscaching
Svarscaching, Ä andra sidan, innebÀr att lagra resultaten av nÀtverksanrop lokalt pÄ klientsidan. NÀr ett efterföljande anrop görs för samma resurs kan det cachade svaret serveras istÀllet för att göra ett nytt nÀtverksanrop. Detta leder till betydande förbÀttringar i:
- Prestanda: Snabbare datahÀmtning minskar laddningstider och förbÀttrar upplevd responsivitet.
- Offline-stöd: AnvÀndare kan komma Ät tidigare hÀmtad data Àven nÀr deras internetanslutning Àr otillgÀnglig eller instabil.
- Minskad serverbelastning: Mindre trafik till servern innebÀr lÀgre infrastrukturkostnader och bÀttre skalbarhet.
Fetch API fungerar sömlöst med webblÀsarens cachningsmekanismer och kan förbÀttras ytterligare med anpassade cachningsstrategier implementerade via Service Workers eller webblÀsarens lagrings-API:er som localStorage eller IndexedDB.
Request Interception med Service Workers
Service Workers Àr hörnstenen för att implementera avancerade mönster för request interception med Fetch API. En Service Worker Àr en JavaScript-fil som körs i bakgrunden, separat frÄn din webbsida, och fungerar som en programmerbar nÀtverksproxy mellan webblÀsaren och nÀtverket.
Vad Àr en Service Worker?
En Service Worker registrerar sig för att lyssna pÄ hÀndelser, varav den viktigaste Àr fetch-hÀndelsen. NÀr ett nÀtverksanrop görs frÄn sidan som Service Workern kontrollerar, tar Service Workern emot en fetch-hÀndelse och kan dÄ bestÀmma hur den ska svara.
Registrera en Service Worker
Det första steget Àr att registrera din Service Worker. Detta görs vanligtvis i din huvudsakliga JavaScript-fil:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log('Service Worker registrerad med scope:', registration.scope);
})
.catch(function(error) {
console.error('Registrering av Service Worker misslyckades:', error);
});
}
SökvÀgen /sw.js pekar pÄ ditt Service Worker-skript.
Service Worker-skriptet (sw.js)
Inuti din sw.js-fil kommer du att lyssna efter fetch-hÀndelsen:
self.addEventListener('fetch', function(event) {
// Logik för att fÄnga upp anropet gÄr hÀr
});
Implementera logik för Request Interception
Inom fetch-hÀndelselyssnaren ger event.request tillgÄng till det inkommande anropsobjektet. Du kan sedan anvÀnda detta för att:
1. Modifiera Request Headers
LÄt oss sÀga att du behöver lÀgga till en API-nyckel i varje utgÄende anrop till en specifik API-slutpunkt. Du kan fÄnga upp anropet, skapa ett nytt med den tillagda headern och sedan fortsÀtta:
self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url);
const apiKey = 'DIN_GLOBALA_API_NYCKEL'; // Ladda frÄn en sÀker kÀlla eller konfiguration
if (url.origin === 'https://api.example.com') {
// Klona anropet sÄ att vi kan modifiera det
const modifiedRequest = new Request(event.request, {
headers: {
'X-API-Key': apiKey,
// Du kan ocksÄ slÄ samman befintliga headers:
// ...Object.fromEntries(event.request.headers.entries()),
// 'X-Custom-Header': 'value'
}
});
// Svara med det modifierade anropet
event.respondWith(fetch(modifiedRequest));
} else {
// För andra anrop, fortsÀtt som vanligt
event.respondWith(fetch(event.request));
}
});
Globala övervÀganden: För globala applikationer kan API-nycklar behöva vara regionspecifika eller hanteras genom en central autentiseringstjÀnst som hanterar geografisk routing. Se till att din interceptionslogik korrekt hÀmtar eller tillÀmpar lÀmplig nyckel för anvÀndarens region.
2. Omdirigera anrop
Du kanske vill omdirigera anrop till en annan server baserat pÄ anvÀndarens plats eller en A/B-testningsstrategi.
self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url);
const userLocation = getUserLocation(); // PlatshÄllare för platslogik
if (url.pathname === '/api/data') {
let targetUrl = url.toString();
if (userLocation === 'europe') {
targetUrl = 'https://api.europe.example.com/data';
} else if (userLocation === 'asia') {
targetUrl = 'https://api.asia.example.com/data';
}
// Klona och omdirigera
const redirectedRequest = new Request(targetUrl, {
method: event.request.method,
headers: event.request.headers,
body: event.request.body,
mode: 'cors'
});
event.respondWith(fetch(redirectedRequest));
} else {
event.respondWith(fetch(event.request));
}
});
function getUserLocation() {
// I en riktig app skulle detta innebÀra GeoIP-uppslag, anvÀndarinstÀllningar eller webblÀsarens geolokaliserings-API.
// För demonstration antar vi en enkel logik.
return 'asia'; // Exempel
}
Globala övervÀganden: Dynamisk omdirigering Àr avgörande för globala appar. Geo-routing kan avsevÀrt minska latensen genom att dirigera anvÀndare till nÀrmaste API-server. Implementeringen av `getUserLocation()` mÄste vara robust och potentiellt anvÀnda IP-geolokaliseringstjÀnster som Àr optimerade för hastighet och noggrannhet över hela vÀrlden.
3. Avbryta anrop
Om ett anrop inte lÀngre Àr relevant (t.ex. om anvÀndaren navigerar bort frÄn sidan), kanske du vill avbryta det.
let ongoingRequests = {};
self.addEventListener('fetch', function(event) {
const requestId = Math.random().toString(36).substring(7);
ongoingRequests[requestId] = event.request;
event.respondWith(
fetch(event.request).finally(() => {
delete ongoingRequests[requestId];
})
);
});
// Exempel pÄ hur du kan avbryta ett anrop frÄn huvudtrÄden (mindre vanligt för interception i sig, men visar kontroll)
function cancelRequest(requestUrl) {
for (const id in ongoingRequests) {
if (ongoingRequests[id].url === requestUrl) {
// Notera: Fetch API har inte ett direkt 'abort' för ett anrop *efter* att det har skickats via SW.
// Detta Àr mer illustrativt. För verklig avbrytning anvÀnds AbortController *innan* fetch.
console.warn(`Försöker avbryta anrop för: ${requestUrl}`);
// Ett mer praktiskt tillvÀgagÄngssÀtt skulle vara att kontrollera om ett anrop fortfarande Àr relevant innan fetch anropas i SW.
break;
}
}
}
Notera: Verklig avbrytning av ett anrop efter att `fetch()` har anropats inom Service Workern Àr komplext. `AbortController` API:et Àr standardmetoden för att avbryta ett `fetch`-anrop, men det mÄste skickas med till sjÀlva `fetch`-anropet, som oftast initieras frÄn huvudtrÄden. Service Workers fÄngar frÀmst upp anrop och bestÀmmer sedan hur de ska svara.
4. Mocka svar för utveckling
Under utvecklingen kan du anvÀnda din Service Worker för att returnera mock-data och dÀrmed kringgÄ det faktiska nÀtverket.
self.addEventListener('fetch', function(event) {
const url = new URL(event.request.url);
if (url.pathname === '/api/users') {
// Kontrollera om det Àr ett GET-anrop
if (event.request.method === 'GET') {
const mockResponse = {
status: 200,
statusText: 'OK',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([
{ id: 1, name: 'Alice', region: 'North America' },
{ id: 2, name: 'Bob', region: 'Europe' },
{ id: 3, name: 'Charlie', region: 'Asia' }
])
};
event.respondWith(new Response(mockResponse.body, mockResponse));
} else {
// Hantera andra metoder om det behövs eller skicka vidare
event.respondWith(fetch(event.request));
}
} else {
event.respondWith(fetch(event.request));
}
});
Globala övervÀganden: Mockning kan inkludera datavariationer som Àr relevanta för olika regioner, vilket hjÀlper utvecklare att testa lokaliserat innehÄll och funktioner utan att krÀva en fullt fungerande global backend-uppsÀttning.
Svarscachningsstrategier med Fetch API
Service Workers Àr ocksÄ otroligt kraftfulla för att implementera sofistikerade strategier för svarscachning. Det Àr hÀr magin med offline-stöd och blixtsnabb datahÀmtning verkligen kommer till sin rÀtt.
Utnyttja webblÀsarens cache
WebblÀsaren har i sig en inbyggd HTTP-cache. NÀr du anvÀnder fetch() utan nÄgon speciell Service Worker-logik kommer webblÀsaren först att kontrollera sin cache. Om ett giltigt, icke-utgÄnget cachat svar hittas kommer det att serveras direkt. Cache-control-headers som skickas av servern (t.ex. Cache-Control: max-age=3600) dikterar hur lÀnge svar anses vara fÀrska.
Anpassad cachning med Service Workers
Service Workers ger dig finkornig kontroll över cachning. Det allmÀnna mönstret innebÀr att fÄnga upp en fetch-hÀndelse, försöka hÀmta svaret frÄn cachen, och om det inte hittas, hÀmta det frÄn nÀtverket och sedan cacha det för framtida anvÀndning.
1. Cache-First-strategi
Detta Àr en vanlig strategi dÀr Service Workern först försöker servera svaret frÄn sin cache. Om det inte hittas i cachen görs ett nÀtverksanrop, svaret serveras frÄn nÀtverket och cachas för nÀsta gÄng.
const CACHE_NAME = 'my-app-v1';
const urlsToCache = [
'/',
'/styles.css',
'/script.js'
];
self.addEventListener('install', function(event) {
// Utför installationssteg
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
console.log('Ăppnade cache');
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request)
.then(function(response) {
// CachetrÀff - returnera svar
if (response) {
return response;
}
// Inte i cachen - hÀmta frÄn nÀtverket
return fetch(event.request).then(
function(response) {
// Kontrollera om vi fick ett giltigt svar
if (!response || response.status !== 200 || response.type !== 'basic') {
return response;
}
// VIKTIGT: Klona svaret. Ett svar Àr en ström
// och eftersom vi vill att webblÀsaren ska konsumera svaret
// samt att cachen ska konsumera svaret, behöver vi
// klona det sÄ att vi har tvÄ strömmar.
const responseToCache = response.clone();
caches.open(CACHE_NAME)
.then(function(cache) {
cache.put(event.request, responseToCache);
});
return response;
}
);
})
);
});
// Valfritt: Rensa gamla cachar nÀr en ny version av SW installeras
self.addEventListener('activate', function(event) {
const cacheWhitelist = [CACHE_NAME];
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
if (cacheWhitelist.indexOf(cacheName) === -1) {
return caches.delete(cacheName);
}
})
);
})
);
});
2. Network-First-strategi
Denna strategi prioriterar att hÀmta fÀrsk data frÄn nÀtverket. Om nÀtverksanropet misslyckas (t.ex. ingen anslutning), faller den tillbaka pÄ det cachade svaret.
self.addEventListener('fetch', function(event) {
event.respondWith(
fetch(event.request).catch(function() {
// Om fetch misslyckas, fall tillbaka pÄ cachen
return caches.match(event.request);
})
);
});
Globala övervÀganden: Network-first Àr utmÀrkt för dynamiskt innehÄll dÀr fÀrskhet Àr avgörande, men du fortfarande vill ha motstÄndskraft för anvÀndare med intermittenta anslutningar, vilket Àr vanligt i mÄnga delar av vÀrlden.
3. Stale-While-Revalidate
Detta Àr en mer avancerad och ofta föredragen strategi för dynamiskt innehÄll. Den serverar det cachade svaret omedelbart (vilket gör att grÀnssnittet kÀnns snabbt) medan den i bakgrunden gör ett nÀtverksanrop för att Ätervalidera cachen. Om nÀtverksanropet returnerar en nyare version, uppdateras cachen.
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
return cache.match(event.request).then(function(cachedResponse) {
// Om cachat svar finns, returnera det omedelbart
if (cachedResponse) {
// Börja hÀmta frÄn nÀtverket i bakgrunden
fetch(event.request).then(function(networkResponse) {
// Om nÀtverkssvaret Àr giltigt, uppdatera cachen
if (networkResponse && networkResponse.status === 200 && networkResponse.type === 'basic') {
cache.put(event.request, networkResponse.clone());
}
}).catch(function() {
// NÀtverksanropet misslyckades, gör ingenting, har redan serverat frÄn cache
});
return cachedResponse;
}
// Inget cachat svar, hÀmta frÄn nÀtverket och cacha det
return fetch(event.request).then(function(networkResponse) {
if (networkResponse && networkResponse.status === 200 && networkResponse.type === 'basic') {
cache.put(event.request, networkResponse.clone());
}
return networkResponse;
});
});
})
);
});
Globala övervĂ€ganden: Denna strategi erbjuder det bĂ€sta av tvĂ„ vĂ€rldar â upplevd hastighet och uppdaterad data. Den Ă€r sĂ€rskilt effektiv för globala applikationer dĂ€r anvĂ€ndare kan vara lĂ„ngt frĂ„n ursprungsservern och uppleva hög latens; de fĂ„r data omedelbart frĂ„n cachen, och cachen uppdateras för efterföljande anrop.
4. Cache-Only-strategi
Denna strategi serverar endast frÄn cachen och gör aldrig ett nÀtverksanrop. Den Àr idealisk för kritiska, oförÀnderliga tillgÄngar eller nÀr offline-first Àr ett absolut krav.
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
// Om svar hittas i cachen, returnera det, annars returnera ett fel eller fallback
return response || new Response('NÀtverksfel - Offline-innehÄll ej tillgÀngligt', { status: 404 });
})
);
});
5. Network-Only-strategi
Denna strategi gör helt enkelt ett nÀtverksanrop och anvÀnder aldrig cachen. Det Àr standardbeteendet för `fetch()` utan en Service Worker, men kan definieras explicit inom en Service Worker för specifika resurser.
self.addEventListener('fetch', function(event) {
event.respondWith(fetch(event.request));
});
Kombinera Request Interception och Svarscaching
Den sanna kraften i Fetch API för globala applikationer framtrÀder nÀr du kombinerar request interception och svarscaching. Din Service Worker kan fungera som en central hubb som orkestrerar komplex nÀtverkslogik.
Exempel: Autentiserade API-anrop med cachning
LÄt oss betrakta en e-handelsapplikation. AnvÀndarprofildata och produktlistor kan vara cachningsbara, men ÄtgÀrder som att lÀgga till varor i en varukorg eller bearbeta en bestÀllning krÀver autentisering och bör hanteras annorlunda.
// I sw.js
const CACHE_NAME = 'my-app-v2';
// Cacha statiska tillgÄngar
self.addEventListener('install', function(event) {
event.waitUntil(
caches.open(CACHE_NAME)
.then(function(cache) {
return cache.addAll([
'/', '/index.html', '/styles.css', '/app.js',
'/images/logo.png'
]);
})
);
});
self.addEventListener('fetch', function(event) {
const requestUrl = new URL(event.request.url);
// Hantera API-anrop
if (requestUrl.origin === 'https://api.globalstore.com') {
// Request Interception: LÀgg till Auth Token för API-anrop
const authHeader = { 'Authorization': `Bearer ${getAuthToken()}` }; // PlatshÄllare
const modifiedRequest = new Request(event.request, {
headers: {
...Object.fromEntries(event.request.headers.entries()),
...authHeader
}
});
// Svarscachningsstrategi: Stale-While-Revalidate för produktkatalog
if (requestUrl.pathname.startsWith('/api/products')) {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
return cache.match(modifiedRequest).then(function(cachedResponse) {
// Om cachat svar finns, returnera det omedelbart
if (cachedResponse) {
// Börja hÀmta frÄn nÀtverket i bakgrunden för uppdateringar
fetch(modifiedRequest).then(function(networkResponse) {
if (networkResponse && networkResponse.status === 200 && networkResponse.type === 'basic') {
cache.put(modifiedRequest, networkResponse.clone());
}
}).catch(function() { /* Ignorera nÀtverksfel hÀr */ });
return cachedResponse;
}
// Inget cachat svar, hÀmta frÄn nÀtverket och cacha det
return fetch(modifiedRequest).then(function(networkResponse) {
if (networkResponse && networkResponse.status === 200 && networkResponse.type === 'basic') {
cache.put(modifiedRequest, networkResponse.clone());
}
return networkResponse;
});
});
})
);
}
// Network-First för anvÀndarspecifik data (t.ex. varukorg, bestÀllningar)
else if (requestUrl.pathname.startsWith('/api/user') || requestUrl.pathname.startsWith('/api/cart')) {
event.respondWith(
fetch(modifiedRequest).catch(function() {
// Fallback till cachen om nÀtverket misslyckas (för offline-visning av tidigare laddad data)
return caches.match(modifiedRequest);
})
);
}
// Network-only för kritiska operationer (t.ex. lÀgga bestÀllning)
else {
event.respondWith(fetch(modifiedRequest));
}
}
// För andra anrop (t.ex. externa tillgÄngar), anvÀnd standard fetch
else {
event.respondWith(fetch(event.request));
}
});
function getAuthToken() {
// Denna funktion behöver hÀmta auth-token, potentiellt frÄn localStorage
// eller en cookie. Var medveten om sÀkerhetskonsekvenserna.
return localStorage.getItem('authToken') || 'guest'; // Exempel
}
Globala övervÀganden:
- Autentisering: `getAuthToken()` mÄste vara robust. För en global app Àr en central identitetsleverantör som hanterar OAuth eller JWT:er vanlig. Se till att tokens lagras sÀkert och Àr tillgÀngliga.
- API-slutpunkter: Exemplet antar en enda API-domÀn. I verkligheten kan du ha regionala API:er, och interceptionslogiken bör ta hÀnsyn till detta, potentiellt genom att anvÀnda anropets URL för att avgöra vilken API-domÀn som ska anropas.
- Offline-anvÀndarÄtgÀrder: För ÄtgÀrder som att lÀgga till i varukorgen offline, skulle du vanligtvis köa ÄtgÀrderna i
IndexedDBoch synkronisera dem nÀr anslutningen ÄterstÀlls. Service Workern kan upptÀcka online/offline-status och hantera denna köhantering.
Implementera cachning för internationaliserat innehÄll
NÀr du hanterar en global publik serverar din applikation troligen innehÄll pÄ flera sprÄk och regioner. Cachningsstrategier mÄste anpassas till detta.
Varierande svar baserat pÄ headers
NÀr du cachar internationaliserat innehÄll Àr det avgörande att sÀkerstÀlla att det cachade svaret matchar anropets sprÄk- och lokalpreferenser. Accept-Language-headern Àr nyckeln hÀr. Du kan anvÀnda den i dina caches.match-anrop.
// Inuti en fetch-hÀndelsehanterare i sw.js
self.addEventListener('fetch', function(event) {
const request = event.request;
const url = new URL(request.url);
if (url.pathname.startsWith('/api/content')) {
event.respondWith(
caches.open(CACHE_NAME).then(function(cache) {
// Skapa en nyckel som inkluderar Accept-Language-header för varierande cache-poster
const cacheKey = new Request(request.url, {
headers: {
'Accept-Language': request.headers.get('Accept-Language') || 'en-US'
}
});
return cache.match(cacheKey).then(function(cachedResponse) {
if (cachedResponse) {
console.log('Serverar frÄn cache för lokal:', request.headers.get('Accept-Language'));
// Potentiellt Ätervalidera i bakgrunden om stale-while-revalidate
return cachedResponse;
}
// HÀmta frÄn nÀtverket och cacha med lokalspecifik nyckel
return fetch(request).then(function(networkResponse) {
if (networkResponse.ok) {
// Klona svar för cachning
const responseToCache = networkResponse.clone();
cache.put(cacheKey, responseToCache);
}
return networkResponse;
});
});
})
);
} else {
event.respondWith(fetch(request));
}
});
Globala övervÀganden:
- `Accept-Language`-header: Se till att din backend korrekt bearbetar `Accept-Language`-headern för att servera lÀmpligt lokaliserat innehÄll. Klientsidan (webblÀsaren) skickar ofta denna header automatiskt baserat pÄ anvÀndarens OS/webblÀsarinstÀllningar.
- `Vary`-header: NÀr du serverar innehÄll frÄn en server som behöver respektera cachning baserat pÄ headers som `Accept-Language`, se till att servern inkluderar en `Vary: Accept-Language`-header i sina svar. Detta talar om för mellanliggande cachar (inklusive webblÀsarens HTTP-cache och Service Worker-cache) att svarsinnehÄllet kan variera baserat pÄ denna header.
- Dynamiskt innehÄll vs. statiska tillgÄngar: Statiska tillgÄngar som bilder eller typsnitt behöver kanske inte variera per lokal, vilket förenklar deras cachning. Dynamiskt innehÄll drar dock stor nytta av lokalmedveten cachning.
Verktyg och bibliotek
Ăven om du kan bygga sofistikerad logik för request interception och cachning direkt med Service Workers och Fetch API, kan flera bibliotek förenkla processen:
- Workbox: En uppsÀttning bibliotek och verktyg frÄn Google som gör det enkelt att implementera en robust Service Worker. Den tillhandahÄller fÀrdiga cachningsstrategier, routing och andra anvÀndbara verktyg, vilket avsevÀrt minskar mÀngden standardkod. Workbox abstraherar bort mycket av komplexiteten i Service Worker-livscykeln och cachehanteringen.
- Axios: Ăven om det inte Ă€r direkt relaterat till Service Workers, Ă€r Axios en populĂ€r HTTP-klient som erbjuder inbyggda interceptorer för anrop och svar. Du kan anvĂ€nda Axios i kombination med en Service Worker för en mer strömlinjeformad hantering av nĂ€tverksanrop pĂ„ klientsidan.
Exempel med Workbox
Workbox förenklar cachningsstrategier avsevÀrt:
// I sw.js (med Workbox)
importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.0.0/workbox-sw.js');
const CACHE_NAME = 'my-app-v2';
// För-cacha viktiga tillgÄngar
workbox.precaching.precacheAndRoute([
'/', '/index.html', '/styles.css', '/app.js',
'/images/logo.png'
]);
// Cacha API-anrop med stale-while-revalidate
workbox.routing.registerRoute(
/https:\/\/api\.globalstore\.com\/api\/products/, // Regex för att matcha produkt-API-URL:er
new workbox.strategies.StaleWhileRevalidate({
cacheName: CACHE_NAME,
plugins: [
// LÀgg eventuellt till cachning för olika lokaler om det behövs
// new workbox.cacheableResponse.CacheableResponsePlugin({
// statuses: [0, 200]
// })
]
})
);
// Cacha anvÀndarspecifik data med network-first-strategi
workbox.routing.registerRoute(
/https:\/\/api\.globalstore\.com\/api\/(user|cart)/, // Regex för anvÀndar-/varukorgs-API
new workbox.strategies.NetworkFirst({
cacheName: CACHE_NAME,
plugins: [
new workbox.expiration.ExpirationPlugin({
// Cacha endast 5 poster, upphör att gÀlla efter 30 dagar
maxEntries: 5,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 dagar
}),
new workbox.cacheableResponse.CacheableResponsePlugin({
statuses: [0, 200]
})
]
})
);
// Network-only för kritiska operationer (exempel)
workbox.routing.registerRoute(
/https:\/\/api\.globalstore\.com\/api\/order/,
new workbox.strategies.NetworkOnly()
);
// Anpassad hanterare för att lÀgga till Authorization-header i alla API-anrop
workbox.routing.registerRoute(
/https:\/\/api\.globalstore\.com/,
new workbox.strategies.NetworkFirst({
cacheName: CACHE_NAME,
plugins: [
{
requestWillFetch: async ({ request, url, event, delta }) => {
const token = localStorage.getItem('authToken');
const headers = new Headers(request.headers);
if (token) {
headers.set('Authorization', `Bearer ${token}`);
}
return new Request(url, { ...request, headers });
}
}
]
})
);
Globala övervÀganden: Workbox-konfigurationer kan skrÀddarsys för internationella behov. Du kan till exempel anvÀnda Workbox avancerade routing för att servera olika cache-versioner baserat pÄ upptÀckt anvÀndarsprÄk eller region, vilket gör det mycket anpassningsbart för en global anvÀndarbas.
BÀsta praxis och övervÀganden för globala applikationer
NÀr du implementerar request interception och svarscaching för en global publik, ha dessa bÀsta praxis i Ätanke:
- Progressive Enhancement: Se till att din applikation Àr funktionell Àven utan avancerade funktioner som Service Workers. KÀrnfunktionaliteten bör fungera pÄ Àldre webblÀsare och i miljöer dÀr Service Workers kanske inte stöds.
- SÀkerhet: Var extremt försiktig nÀr du hanterar kÀnslig data som autentiseringstokens under request interception. Lagra tokens sÀkert (t.ex. med HttpOnly-cookies dÀr det Àr lÀmpligt, eller sÀkra lagringsmekanismer). HÄrdkoda aldrig hemligheter.
- Cache-invalidering: Att implementera en robust strategi för cache-invalidering Ă€r avgörande. Inaktuell data kan vara vĂ€rre Ă€n ingen data alls. ĂvervĂ€g tidsbaserad utgĂ„ng, versionering och hĂ€ndelsedriven invalidering.
- Prestandaövervakning: Ăvervaka kontinuerligt prestandan för din applikation i olika regioner och nĂ€tverksförhĂ„llanden. Verktyg som Lighthouse, WebPageTest och RUM (Real User Monitoring) Ă€r ovĂ€rderliga.
- Felhantering: Designa din interceptions- och cachningslogik för att elegant hantera nÀtverksfel, serverproblem och ovÀntade svar. Ge meningsfulla fallback-upplevelser för anvÀndarna.
- Vikten av `Vary`-header: För cachade svar som beror pÄ request-headers (som `Accept-Language`), se till att din backend skickar `Vary`-headern korrekt. Detta Àr grundlÀggande för korrekt cachningsbeteende över olika anvÀndarpreferenser.
- Resursoptimering: Cacha bara det som Àr nödvÀndigt. Stora, sÀllan Àndrade tillgÄngar Àr bra kandidater för aggressiv cachning. Ofta Àndrad dynamisk data krÀver mer dynamiska cachningsstrategier.
- Paketstorlek: Var medveten om storleken pÄ ditt Service Worker-skript. En alltför stor SW kan vara lÄngsam att installera och aktivera, vilket pÄverkar den initiala anvÀndarupplevelsen.
- AnvĂ€ndarkontroll: ĂvervĂ€g att ge anvĂ€ndarna viss kontroll över cachningsbeteendet om tillĂ€mpligt, Ă€ven om detta Ă€r mindre vanligt för typiska webbapplikationer.
Slutsats
Request interception och svarscaching, sÀrskilt nÀr de drivs av Service Workers och Fetch API, Àr oumbÀrliga verktyg för att bygga högpresterande, motstÄndskraftiga globala webbapplikationer. Genom att fÄnga upp anrop fÄr du kontroll över hur din applikation kommunicerar med servrar, vilket möjliggör dynamiska justeringar för autentisering, routing och mer. Genom att implementera smarta cachningsstrategier förbÀttrar du drastiskt laddningstider, möjliggör offline-Ätkomst och minskar serverbelastningen.
För en internationell publik Àr dessa tekniker inte bara optimeringar; de Àr grundlÀggande för att leverera en konsekvent och positiv anvÀndarupplevelse, oavsett geografisk plats eller nÀtverksförhÄllanden. Oavsett om du bygger en global e-handelsplattform, en innehÄllstung nyhetsportal eller en SaaS-applikation, kommer att bemÀstra de avancerade funktionerna i Fetch API att sÀrskilja din applikation.
Kom ihÄg att utnyttja verktyg som Workbox för att pÄskynda utvecklingen och sÀkerstÀlla att dina strategier Àr robusta. Testa och övervaka kontinuerligt din applikations prestanda över hela vÀrlden för att förfina din strategi och ge bÀsta möjliga upplevelse för varje anvÀndare.